package cn.donting.plugin.spring.boot.starter;

import cn.donting.plugin.spring.boot.starter.properties.PluginProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * FileJson 的文件存储插件信息
 * @author donting
 *  2020-05-13 下午5:22
 */
@Component
public class FileJsonPluginDb implements PluginDb {

    private final String dbFilePath;
    private final File dnFile;

    public FileJsonPluginDb(PluginProperties plugProperties) throws IOException {
        dbFilePath = plugProperties.getPath() + File.separator + "plugDb.json";
        dnFile = new File(dbFilePath);
        if (!dnFile.exists()) {
            File pr = new File(plugProperties.getPath());
            if (!pr.exists()) {
                pr.mkdirs();
            }
            dnFile.createNewFile();
            DbInfo dbInfo = new DbInfo();
            save(dbInfo);
        }
    }

    private void save(DbInfo dbInfo) throws IOException {
        String s = JSON.toJSONString(dbInfo);
        FileOutputStream fileOutputStream = new FileOutputStream(dnFile);
        fileOutputStream.write(s.getBytes(StandardCharsets.UTF_8));
        fileOutputStream.flush();
        fileOutputStream.close();
    }

    @Override
    public Map<String, PluginDbInfo> read() throws IOException {
        FileInputStream fileOutputStream = new FileInputStream(dnFile);
        int available = fileOutputStream.available();
        byte[] bytes = new byte[available];
        fileOutputStream.read(bytes);
        fileOutputStream.close();
        String s = new String(bytes, StandardCharsets.UTF_8);
        DbInfo dbInfo = JSONObject.parseObject(s, DbInfo.class);
        Map<String, PluginDbInfo> plugs = dbInfo.getPlugins();
        return plugs;
    }

    @Override
    public void install(Plugin plugin, File file) throws IOException {
        Map<String, PluginDbInfo> read = read();
        DbInfo dbInfo = new DbInfo();
        PluginDbInfo plugInstallInfo = getPluginInstallInfo(plugin, file.getPath());
        read.put(plugInstallInfo.getId(), plugInstallInfo);
        dbInfo.setPlugins(read);
        save(dbInfo);
    }

    @Override
    public PluginDbInfo uninstall(String id) throws IOException {
        Map<String, PluginDbInfo> read = read();
        PluginDbInfo remove = read.remove(id);
        DbInfo dbInfo = new DbInfo(read);
        save(dbInfo);
        return remove;
    }

    @Override
    public void stop(String id) throws IOException {
        Map<String, PluginDbInfo> read = read();
        PluginDbInfo plugInstallInfo = read.get(id);
        if (plugInstallInfo == null) {
            throw new RuntimeException(id + " not install");
        }
        plugInstallInfo.setStateTime(System.currentTimeMillis());
        plugInstallInfo.setState(PluginDbInfo.StateEnum.STOP);
        DbInfo dbInfo = new DbInfo(read);
        save(dbInfo);
    }

    @Override
    public String start(String id) throws IOException {
        Map<String, PluginDbInfo> read = read();
        PluginDbInfo plugInstallInfo = read.get(id);
        if (plugInstallInfo == null) {
            throw new RuntimeException(id + " not install");
        }
        plugInstallInfo.setStateTime(System.currentTimeMillis());
        plugInstallInfo.setState(PluginDbInfo.StateEnum.RUNNING);
        DbInfo dbInfo = new DbInfo(read);
        save(dbInfo);
        return plugInstallInfo.getPath();
    }

    @Override
    public void update(Plugin plugin, File file) throws IOException {
        Map<String, PluginDbInfo> read = read();
        String id = plugin.id();
        read.get(id);
        DbInfo dbInfo = new DbInfo();
        PluginDbInfo plugInstallInfo = getPluginInstallInfo(plugin, file.getPath());
        read.put(plugInstallInfo.getId(), plugInstallInfo);
        dbInfo.setPlugins(read);
        save(dbInfo);
    }

    @Override
    public boolean isInstall(String pluginId) throws IOException {
        return  read().containsKey(pluginId);
    }

    private PluginDbInfo getPluginInstallInfo(Plugin plugin, String filePath) {
        PluginDbInfo plugInstallInfo = new PluginDbInfo();
        plugInstallInfo.setId(plugin.id());
        plugInstallInfo.setAuthor(plugin.author());
        plugInstallInfo.setVersion(plugin.version());
        plugInstallInfo.setVersionCode(plugin.versionCode());
        plugInstallInfo.setPath(filePath);
        plugInstallInfo.setName(plugin.name());
        plugInstallInfo.setInstallTime(System.currentTimeMillis());
        plugInstallInfo.setStateTime(System.currentTimeMillis());
        plugInstallInfo.setState(PluginDbInfo.StateEnum.RUNNING);
        return plugInstallInfo;
    }


    @Getter
    public static class DbInfo {
        private String version = "v1.0";
        @Setter
        private Map<String, PluginDbInfo> plugins = new HashMap<>();

        public DbInfo() {
        }

        public DbInfo(Map<String, PluginDbInfo> plugs) {
            this.plugins = plugs;
        }
    }
}
